package com.wei.web.middleware.httpfilter.auth.server;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.wei.web.middleware.httpfilter.auth.security.model.SecurityConfigDTO;
import com.wei.web.middleware.httpfilter.auth.server.method.DefaultServerAuthMethod;
import com.wei.web.middleware.httpfilter.auth.server.method.IServerAuthMethod;
import com.wei.web.middleware.httpfilter.auth.server.method.ZecoChatAuthMethod;
import com.wei.web.middleware.httpfilter.auth.server.model.ServerAuthConfig;
import com.wei.web.middleware.httpfilter.enums.ErrorEnum;
import com.wei.web.middleware.httpfilter.exceptions.FASException;
import com.wei.web.middleware.httpfilter.filter.init.FilterInitialize;
import com.wei.web.middleware.httpfilter.registrar.filter.CorsFilterRegistrar;
import com.wei.web.middleware.httpfilter.registrar.model.FilterConfigDTO;
import com.wei.web.middleware.httpfilter.registrar.security.SecurityAuthRegistrar;
import com.wei.web.middleware.httpfilter.utils.FileUtil;
import com.wei.web.middleware.httpfilter.utils.ResponseWrapper;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class ServerAuthFilter extends OncePerRequestFilter implements FilterInitialize {

    public static final String DEFAULT_CONFIG_LOCATION = "auth/server_auth_config.json";

    public static ConcurrentHashMap<String, IServerAuthMethod> serverAuthMethodMap = new ConcurrentHashMap<>();

    static {
        DefaultServerAuthMethod defaultServerAuthMethod = new DefaultServerAuthMethod();
        ZecoChatAuthMethod zecoChatAuthMethod = new ZecoChatAuthMethod();
        serverAuthMethodMap.put(defaultServerAuthMethod.getType(), defaultServerAuthMethod);
        serverAuthMethodMap.put(zecoChatAuthMethod.getType(), zecoChatAuthMethod);
    }

    public ConcurrentHashMap<AntPathRequestMatcher, ServerAuthConfig.AuthConfigDTO> pathPatternToAuthMap = new ConcurrentHashMap<>();


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        System.out.println("server auth");
        try {
            for (Map.Entry<AntPathRequestMatcher, ServerAuthConfig.AuthConfigDTO> authEntry : pathPatternToAuthMap.entrySet()) {
                if (authEntry.getKey().matches(request)) {
                    ServerAuthConfig.AuthConfigDTO authConfigDTO = authEntry.getValue();
                    if (authConfigDTO.getLocalAccess()) {
                        doLocalAuth();
                    }
                    String jwtToken = validateAndGetJwtTokenByIssueAndAudience(request);


                    IServerAuthMethod serverAuthMethod = serverAuthMethodMap.get(authConfigDTO.getAuthType());
                    serverAuthMethod.auth(request, jwtToken, authConfigDTO.getAuthConfig());
                    break;
                }
            }
        } catch (FASException be) {
            log.error("Bot detect intent jwt token verification failed.", be);
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            ResponseWrapper.responseError(be.getError(), response);
            return;
        } catch (Exception e) {
            log.error("Bot detect intent jwt token verification failed.", e);
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            ResponseWrapper.responseError(ErrorEnum.JWT_TOKEN_INVALID,  response);
            return;
        }
        filterChain.doFilter(request, response);
    }

    @SneakyThrows
    @Override
    public void init(FilterConfigDTO filterConfigDTO) {
        ServerAuthConfig serverAuthConfig = getServerAuthConfig(filterConfigDTO);
        for (ServerAuthConfig.AuthConfigDTO authConfigDTO : serverAuthConfig.getAuthList()) {
            for (String urlPattern : authConfigDTO.getUrlPatterns()) {
                pathPatternToAuthMap.put(new AntPathRequestMatcher(urlPattern), authConfigDTO);
            }
        }
    }

    private Boolean doLocalAuth() {
        return true;
    }

    private String validateAndGetJwtTokenByIssueAndAudience(HttpServletRequest request) {
        return "";
    }

    private ServerAuthConfig getServerAuthConfig(FilterConfigDTO filterConfigDTO) throws IOException {
        ClassLoader classLoader = ServerAuthFilter.class.getClassLoader();
        String configStr = FileUtil.getContent(getConfigLocation(filterConfigDTO), classLoader);
        ServerAuthConfig serverAuthConfig = JSONObject.parseObject(configStr, new TypeReference<>() {});
        return serverAuthConfig;
    }

    private String getConfigLocation(FilterConfigDTO filterConfigDTO) {
        String configFilePath = filterConfigDTO.getConfig().get("config_file").toString().trim();
        if (StringUtils.isNotEmpty(configFilePath)) {
            return configFilePath;
        }
        return DEFAULT_CONFIG_LOCATION;
    }
}
